/******************************************************************************\
 *                                                                              *
 *     File: Dierentuin_cc                                                      *
 *                                                                              *
 *   Author: Jan Meuleman / Douwe A. van Twillert                               *
 *  Purpose: de definitie (implementatie) van de klasse Dierentuin              *
 *  Version: 1.0      MEM 20020124                                              *
 *           - eerste versie                                                    *
 *  Version: 1.1      TWI 20080218                                              *
 *           - header aangepast voor duidelijk kunnen printen                   *
 *           - kleine aanpassingen om het half werkend te krijgen               *
 *                                                                              *
\******************************************************************************/

#include "Dierentuin.h"

/*
 *   Constructor
 */
Dierentuin::Dierentuin(string een_naam) {
    de_naam = een_naam;
    werknemers = new map<int, Werknemer*>();
    beschikbareWerknemerNummers = new vector<int>;
    beschikbareDierNummers = new vector<int>;
    dieren = new map<int, Dier*>();
    kooien = new map<string, Kooi*>();
    hoogsteDierNummer = 0;
    hoogsteWerknemernummer = 0;
    vrijkaarten = new list<int>();
}

map<string, Kooi*>* Dierentuin::getKooien() {
    return kooien;
}

/*
 *   Destructor
 */
Dierentuin::~Dierentuin() {
    //delete werknemers
    for (map<int, Werknemer*>::iterator iter = werknemers->begin(); iter != werknemers->end(); ++iter) {
        delete (*iter).second;
    }
    //delete dieren
    for (map<int, Dier*>::iterator iter = dieren->begin(); iter != dieren->end(); ++iter) {
        delete (*iter).second;
    }
    //delete kooien
    for (map<string, Kooi*>::iterator iter = kooien->begin(); iter != kooien->end(); ++iter) {
        delete (*iter).second;
    }
    delete werknemers;
    delete dieren;
    delete beschikbareDierNummers;
    delete beschikbareWerknemerNummers;
    delete vrijkaarten;

    delete kooien;
}

/*
 *   Dierentuin::getNaam()
 */
string Dierentuin::getNaam() {
    return de_naam;
}

list<int>* Dierentuin::getVrijkaarten(){
	return vrijkaarten;
}

void Dierentuin::addVrijkaart(int vrijkaart){
	cout << "Nummer toegevoegd: " << vrijkaart << endl;
	vrijkaarten->push_back(vrijkaart);
}

bool Dierentuin::controleerKaart(int vrijkaart){
	Bond* bond = Bond::getInstance();
	return bond->controleerKaartje(vrijkaart);
}

/*
 *   Dierentuin::dierToevoegen()
 */
void Dierentuin::dierToevoegen(string dierNaam, int dierLeeftijd) {
    assert(dierLeeftijd >= 0);
    // maak een nieuw dier en stop het in de lijst van dieren
    int nr = getLaagsteBeschikbareNummer("dier");

    dieren->insert(map<int, Dier*>::value_type(nr, new Dier(dierNaam, dierLeeftijd)));
}

/*
 *   Dierentuin::dierVerwijderen()
 */
void Dierentuin::dierVerwijderen(int nummer) {
    assert(nummer > 0);
    if (dieren->count(nummer) != 0) {
        dieren->erase(nummer);
    } else {
        cout << "Dier niet gevonden, kies opnieuw" << endl;
        verwijderen("dier");
    }

    //Zet nummer op beschikbaar
    beschikbareDierNummers->push_back(nummer);
    sort(beschikbareDierNummers->begin(), beschikbareDierNummers->end());

}

/*
 *   Dierentuin::werknemerVerwijderen()
 */
void Dierentuin::werknemerVerwijderen(int nummer) {
    assert(nummer > 0);
    if (werknemers->count(nummer) != 0) {
        werknemers->erase(nummer);
    } else {
        cout << "Werknemer niet gevonden, kies opnieuw" << endl;
        verwijderen("werknemer");
    }

    //Zet nummer als beschikbaar
    beschikbareWerknemerNummers->push_back(nummer);
    sort(beschikbareWerknemerNummers->begin(), beschikbareWerknemerNummers->end());

}

int Dierentuin::getLaagsteBeschikbareNummer(string option) {
    int nr = -1;

    if (option == "dier") {

        if (beschikbareDierNummers->empty()) {
            hoogsteDierNummer += 1;
            nr = hoogsteDierNummer;
        } else {
            nr = beschikbareDierNummers->at(0);
            beschikbareDierNummers->erase(beschikbareDierNummers->begin());
        }

    } else if (option == "werknemer") {
        if (beschikbareWerknemerNummers->empty()) {
            hoogsteWerknemernummer += 1;
            nr = hoogsteWerknemernummer;
        } else {
            nr = beschikbareWerknemerNummers->at(0);
            beschikbareWerknemerNummers->erase(beschikbareWerknemerNummers->begin());
        }
    }
    return nr;
}

Werknemer* Dierentuin::getWerknemer(int nummer) {
    assert(nummer > 0);

    if (werknemers->count(nummer) != 0) {
        return werknemers->find(nummer)->second;
        //return werknemers->at(nummer);
    }

    return 0;
}

Dier* Dierentuin::getDier(int nummer) {
    assert(nummer > 0);

    if (dieren->count(nummer) != 0) {
        return dieren->find(nummer)->second;
        //return dieren->at(nummer);
    }

    return 0;
}

void Dierentuin::toevoegen(string option) {
    if (option == "dier") {
        string dierNaam;
        int dierLeeftijd;

        cout << endl << "Geef op een regel, gescheiden door spatie(s)"
                " de naam en de leeftijd van het dier op"
                << endl;

        // lees de gegevens in
        cin >> dierNaam >> dierLeeftijd;
        dierToevoegen(dierNaam, dierLeeftijd);
    } else if (option == "werknemer") {
        string werknemerNaam;
        int werknemerLeeftijd;
        string categorie;

        cout << endl << "Geef op een regel, gescheiden door spatie(s)"
                " de naam, de leeftijd en de categorie ( oppasser, administrateur of manager) van de werknemer op"
                << endl;

        // lees de gegevens in
        cin >> werknemerNaam >> werknemerLeeftijd >> categorie;
        werknemerToevoegen(werknemerNaam, werknemerLeeftijd, categorie);
    } else if (option == "kooi") {
        string diersoort;

        cout << "Geef de naam op van de diersoort die in de kooi komt" << endl;
        cin >> diersoort;
        kooiToevoegen(diersoort);
    }
}

void Dierentuin::verwijderen(string option) {
    if (option == "dier") {
        int nummer;

        //print dieren
        overzichtDieren();

        cout << "Geef het nummer op van de werknemer die verwijderd moet worden" << endl;
        cin >> nummer;
        dierVerwijderen(nummer);
    } else if (option == "werknemer") {
        int nummer;

        //print werknemers
        overzichtWerknemers();

        cout << "Geef het nummer op van de werknemer die verwijderd moet worden" << endl;
        cin >> nummer;
        werknemerVerwijderen(nummer);
    }
}

Kooi* Dierentuin::kooiToewijzen() {
    string kooinaam;

    //print kooien
    overzichtKooien();

    cout << "Geef de naam op van de kooi die toegewezen moet worden, druk e om te stoppen" << endl;
    cin >> kooinaam;

    if (kooien->count(kooinaam) != 0) {
        return kooien->find(kooinaam)->second;
    } else {
        if (kooinaam == "e") {
            return new Kooi("dieren");
        }
        cout << "Kooi bestaat niet" << endl;
        kooiToewijzen();
    }
    return 0;
}

void Dierentuin::werknemerToevoegen(Werknemer* w) {
    assert(w->getLeeftijd() > 15);
    int nr = getLaagsteBeschikbareNummer("werknemer");
    werknemers->insert(map<int, Werknemer*>::value_type(nr, w));
}

/*
 *   Dierentuin::werknemerToevoegen()
 */
void Dierentuin::werknemerToevoegen(string werknemerNaam, int werknemerLeeftijd, string categorie) {
    assert(werknemerLeeftijd > 15);
    // maak een nieuw dier en stop het in de lijst van dieren
    int nr = getLaagsteBeschikbareNummer("werknemer");

    if (categorie == "administrateur") {
        werknemers->insert(map<int, Werknemer*>::value_type(nr, new Administrateur(werknemerNaam, werknemerLeeftijd)));
    } else if (categorie == "oppasser") {
        cout << "Geef een kooi op die oppasser " << werknemerNaam << " toegewezen krijgt" << endl;
        Kooi* kooi = kooiToewijzen();
        werknemers->insert(map<int, Werknemer*>::value_type(nr, new Oppasser(werknemerNaam, werknemerLeeftijd, kooi)));
        //voeg een nieuwe Oppasser toe
    } else if (categorie == "manager") {
        //managerToevoegen(werknemerNaam, werknemerLeeftijd);
        werknemers->insert(map<int, Werknemer*>::value_type(nr, new Manager(werknemerNaam, werknemerLeeftijd, 0)));
    } else {
        cout << "Niet bestaande soort werknemer" << endl;
    }

    //  werknemers->insert(map<int, Werknemer*>::value_type(nr, new Werknemer(werknemerNaam, werknemerLeeftijd)));
}

/*
 *   Dierentuin::overzichtDieren()
 */
void Dierentuin::overzichtDieren() {
    cout << "Lijst van alle dieren" << endl;
    for (map<int, Dier*>::iterator iter = dieren->begin(); iter != dieren->end(); ++iter) {
        cout << (*iter).first << "\t";
        (*iter).second->drukaf();
    }
}

/*
 *   Dierentuin::overzichtWerknemers()
 */
void Dierentuin::overzichtWerknemers() {
    cout << "Lijst van alle werknemers" << endl;
    for (map<int, Werknemer*>::iterator iter = werknemers->begin(); iter != werknemers->end(); ++iter) {
        cout << (*iter).first << "\t";
        (*iter).second->drukaf();
    }
}

int Dierentuin::getSalarisPost() {
    int totSalaris = 0;
    for (map<int, Werknemer*>::iterator iter = werknemers->begin(); iter != werknemers->end(); ++iter) {
        totSalaris += iter->second->getSalaris();
    }
    return totSalaris;
}

void Dierentuin::overzichtKooien() {
    cout << "Lijst van alle Kooien" << endl;
    for (map<string, Kooi*>::iterator iter = kooien->begin(); iter != kooien->end(); ++iter) {
        cout << iter->first << "\t";
        cout << "Aantal dieren in kooi: " << iter->second->getAantalDieren() << endl;
    }
}

void Dierentuin::managerToevoegen(string naam, int werknemerLeeftijd) {
    vector<int>* chosenOnes = new vector<int>();
    string input = "";
    int intPut;
    while (input != "e") {
        overzichtWerknemers();
        cout << "Selecteer 1 werknemer door zijn of haar nummer in te voeren en druk op enter. Om te stoppen, druk op e." << endl;
        cin >> input;
        stringstream myStringStream(input);
        myStringStream >> intPut;
        bool found = false;
        for (vector<int>::iterator iter = chosenOnes->begin(); iter != chosenOnes->end() && !found; ++iter) {
            if (intPut == (*iter)) {
                found = true;
                cout << "Dit nummer is al geselecteerd. Selecteer alstublieft een ander of druk op e" << endl;
            }
        }
        if (!found) {
            chosenOnes->push_back(intPut);
        }
    }
    list<Werknemer*>* ondergeschikten = new list<Werknemer*>();
    for (vector<int>::iterator iter = chosenOnes->begin(); iter != chosenOnes->end(); ++iter) {
        Werknemer* werknemer = werknemers->find((*iter))->second;
        ondergeschikten->push_front(werknemer);
    }
    werknemers->insert(map<int, Werknemer*>::value_type(getLaagsteBeschikbareNummer("werknemer"), new Manager(naam, werknemerLeeftijd, ondergeschikten)));
    delete chosenOnes;
}

void Dierentuin::kooiToevoegen(string diersoort) {

    kooien->insert(make_pair(diersoort, new Kooi(diersoort)));
}

ostream& operator<<(ostream& os, Dierentuin* dt) {
    os << dt->getNaam() << endl;
    for (map<int, Werknemer*>::iterator iter = dt->werknemers->begin(); iter != dt->werknemers->end(); ++iter) {
        os << iter->second;
    }
    os << endl << endl;
    return os;
}
